import asyncio
import os
from fastapi import APIRouter, Depends, Query, BackgroundTasks
from sqlalchemy.orm import Session
from sqlalchemy import distinct
from typing import Optional
from pydantic import BaseModel

from api.database import get_db
from api.model.user import User
from api.model.email_account import EmailAccount
from api.model.email_folder import EmailFolder
from api.controller.auth import get_current_user
from api.schemas.email.account import EmailAccount as EmailAccountResponse, EmailAccountCreate, EmailAccountUpdate
from api.utils.response import success, fail
from api.service.email_service import EmailService
from api.utils.cache import cache
from api.utils.logger import get_logger
from api.utils.helpers import get_beijing_time
from api.utils.async_helper import run_in_executor

# 初始化日志
logger = get_logger("email_accounts")

# 用于验证的模型，password是可选的，以便在更新时处理
class EmailAccountValidate(BaseModel):
    name: str
    email: str
    imap_server: str
    imap_port: int = 993
    imap_ssl: bool = True
    smtp_server: str
    smtp_port: int = 465
    smtp_ssl: bool = True
    password: Optional[str] = None
    proxy_id: Optional[int] = None

class AccountOrderUpdate(BaseModel):
    account_ids: list[int]

class FolderCreate(BaseModel):
    folder_name: str
    parent_folder: Optional[str] = None

class FolderRename(BaseModel):
    old_dir: str
    new_dir: str

class FolderDelete(BaseModel):
    folder_name: str

router = APIRouter()

@router.get("")
async def get_email_accounts(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取当前用户的邮箱账户列表
    """
    accounts = db.query(EmailAccount).filter(
        EmailAccount.user_id == current_user.id
    ).order_by(EmailAccount.display_order).all()
    
    # 显式转换为 Pydantic 模型列表以避免序列化问题
    response_accounts = [EmailAccountResponse.from_orm(acc) for acc in accounts]
    return success(response_accounts)

@router.post("")
async def create_email_account(
    account: EmailAccountCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    创建邮箱账户
    """
    # 检查邮箱是否已存在
    existing_account = db.query(EmailAccount).filter(
        EmailAccount.email == account.email,
        EmailAccount.user_id == current_user.id
    ).first()
    if existing_account:
        return fail("该邮箱账户已存在")

    db_account = EmailAccount(
        user_id=current_user.id,
        name=account.name,
        email=account.email,
        password=account.password,  # 在实际应用中，这里应该是加密后的密码
        imap_server=account.imap_server,
        imap_port=account.imap_port,
        imap_ssl=account.imap_ssl,
        smtp_server=account.smtp_server,
        smtp_port=account.smtp_port,
        smtp_ssl=account.smtp_ssl
    )
    db.add(db_account)
    db.commit()
    db.refresh(db_account)

    # 将新账户加入同步队列
    try:
        from api.service.sync_manager import sync_manager
        await sync_manager.add_account(db_account.id)
        logger.info(f"已将新账户 {db_account.id} 加入同步队列")
    except Exception as e:
        logger.error(f"将账户 {db_account.id} 加入同步队列失败: {e}", exc_info=True)

    return success(db_account, msg="邮箱账户添加成功")

@router.post("/validate")
async def validate_email_account(
    account: EmailAccountValidate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    验证邮箱账户配置。
    - 如果提供了密码，则使用新密码验证。
    - 如果未提供密码，则从数据库中查找现有账户的密码进行验证。
    - 支持使用代理进行测试
    """
    password_to_use = account.password
    
    # 如果请求中没有密码，尝试从数据库中获取
    if not password_to_use:
        existing_account = db.query(EmailAccount).filter(
            EmailAccount.email == account.email,
            EmailAccount.user_id == current_user.id
        ).first()
        if existing_account:
            password_to_use = existing_account.password
        else:
            # 在创建新账户的场景下，密码是必需的
            return fail("密码是必填项")

    # 使用 EmailService 验证账户配置（包含代理支持）- 异步执行
    success_flag, error_message = await run_in_executor(
        EmailService.validate_account_config,
        email=account.email,
        password=password_to_use,
        imap_server=account.imap_server,
        imap_port=account.imap_port,
        imap_ssl=account.imap_ssl,
        smtp_server=account.smtp_server,
        smtp_port=account.smtp_port,
        smtp_ssl=account.smtp_ssl,
        proxy_id=getattr(account, 'proxy_id', None),
        timeout=60.0
    )
    
    if success_flag:
        return success(msg=error_message)
    else:
        return fail(error_message)

@router.put("/order")
async def update_account_order(
    payload: AccountOrderUpdate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    更新邮箱账户的显示顺序
    """
    for index, account_id in enumerate(payload.account_ids):
        account = db.query(EmailAccount).filter(
            EmailAccount.id == account_id,
            EmailAccount.user_id == current_user.id
        ).first()
        if account:
            account.display_order = index
    
    db.commit()
    return success(msg="账户顺序已更新")

@router.get("/folders")
async def get_all_accounts_folders(
    force_refresh: bool = Query(default=False, description="是否强制刷新缓存"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    批量获取当前用户所有邮箱账户的文件夹列表
    返回格式: { account_id: [folders] }
    用于减少初始加载时的请求数
    """
    accounts = db.query(EmailAccount).filter(
        EmailAccount.user_id == current_user.id
    ).order_by(EmailAccount.display_order).all()

    result = {}

    for account in accounts:
        # 缓存键：account_folders:{account_id}
        cache_key = f"account_folders:{account.id}"

        # 尝试从缓存读取
        if not force_refresh:
            cached_data = cache.get(cache_key)
            if cached_data is not None:
                final_folders = cached_data.get("final_folders", [])
                result[str(account.id)] = final_folders
                continue

        # 如果账户被禁用且缓存不存在，直接使用数据库文件夹+固定文件夹
        if not account.is_active:
            logger.info(f"账户 {account.id} 已禁用，使用数据库文件夹+固定文件夹")
            
            # 固定文件夹顶部
            fixed_folders_top = [
                {"name": "INBOX", "display_name": "收件箱"},
                {"name": "UNREAD", "display_name": "未读邮件"},
            ]
            
            # 固定文件夹底部
            fixed_folders_bottom = [
                {"name": "Drafts", "display_name": "草稿箱"},
                {"name": "Sent", "display_name": "已发送"},
                {"name": "Junk", "display_name": "垃圾邮件"},
                {"name": "Trash", "display_name": "已删除"},
            ]
            
            # 从数据库获取该账户的所有文件夹名称（去重）
            db_folders = db.query(distinct(EmailFolder.folder_name)).filter(
                EmailFolder.email_account_id == account.id
            ).all()
            
            # 收集固定文件夹名称
            fixed_folder_names = {f["name"] for f in fixed_folders_top + fixed_folders_bottom}
            
            # 提取自定义文件夹（不在固定列表中的）
            custom_folders = []
            for (folder_name,) in db_folders:
                if folder_name and folder_name not in fixed_folder_names:
                    custom_folders.append({
                        "name": folder_name,
                        "display_name": folder_name
                    })
            
            # 按照：顶部固定 + 自定义 + 底部固定 的顺序组合
            final_folders = fixed_folders_top + custom_folders + fixed_folders_bottom
            result[str(account.id)] = final_folders
            continue

        # 对于启用的账户，使用 EmailService 获取文件夹列表 - 异步执行
        try:
            email_service = EmailService(account=account)
            final_folders, folder_mapping = await run_in_executor(
                email_service.get_folders_list,
                force_refresh,
                timeout=60.0
            )
            
            # 缓存文件夹映射和最终列表（24小时过期）
            cache_data = {
                "folder_mapping": folder_mapping,
                "final_folders": final_folders
            }
            cache.set(cache_key, cache_data, expire=86400)

            result[str(account.id)] = final_folders
        except Exception as e:
            logger.error(f"批量获取账户 {account.id} 文件夹失败: {e}")
            # 即使获取失败，也返回固定文件夹列表
            fixed_folders_top = [
                {"name": "INBOX", "display_name": "收件箱"},
                {"name": "UNREAD", "display_name": "未读邮件"},
            ]
            fixed_folders_bottom = [
                {"name": "Drafts", "display_name": "草稿箱"},
                {"name": "Sent", "display_name": "已发送"},
                {"name": "Junk", "display_name": "垃圾邮件"},
                {"name": "Trash", "display_name": "已删除"},
            ]
            final_folders = fixed_folders_top + fixed_folders_bottom
            result[str(account.id)] = final_folders

    logger.info(f"批量获取完成，共获取 {len(result)} 个账户的文件夹")
    return success(result)

@router.get("/{account_id}")
async def get_email_account(
    account_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取指定邮箱账户信息
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")
    return success(account)

@router.put("/{account_id}")
async def update_email_account(
    account_id: int,
    account_update: EmailAccountUpdate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    更新邮箱账户信息
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")
    
    update_data = account_update.dict(exclude_unset=True)
    for field, value in update_data.items():
        setattr(account, field, value)
    
    db.commit()
    db.refresh(account)
    return success(account, msg="邮箱账户更新成功")

@router.delete("/{account_id}")
async def delete_email_account(
    account_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    删除邮箱账户
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    # 先停止该账户的同步任务
    try:
        from api.service.sync_manager import sync_manager
        await sync_manager.remove_account(account_id)
        logger.info(f"已停止账户 {account_id} 的同步任务")
    except Exception as e:
        logger.error(f"停止账户 {account_id} 的同步任务失败: {e}", exc_info=True)

    # 删除账户
    db.delete(account)
    db.commit()
    return success(msg="邮箱账户删除成功")

@router.post("/{account_id}/sync")
async def sync_email_account(
    account_id: int,
    sync_type: str = Query(default='manual', description="同步类型：manual(手动) 或 history(历史)"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    触发邮箱同步任务
    - manual: 手动同步，立即执行，不受时间锁限制
    - history: 历史邮件同步，用于首次同步或补充历史邮件
    
    注意：因为FastAPI服务和同步服务是两个独立进程，
    这里通过缓存系统实现跨进程通信
    """
    logger.info(f"[API请求] 收到同步请求 [账户ID:{account_id}] [类型:{sync_type}] [用户ID:{current_user.id}]")
    
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    logger.info(f"[API请求] 账户信息 [邮箱:{account.email}] [当前状态:{account.sync_status}]")

    # 检查账户是否正在同步中
    if account.sync_status == 'syncing':
        return fail("该账户正在同步中，请稍后再试")

    try:
        # 使用缓存系统触发跨进程同步
        trigger_key = f"sync_trigger:{account_id}"
        trigger_data = {
            'type': sync_type,
            'timestamp': get_beijing_time().timestamp(),
            'user_id': current_user.id
        }
        cache.set(trigger_key, trigger_data, expire=60)  # 60秒过期，避免重复触发
        
        logger.info(f"[API请求] ✓ 同步触发器已设置 [缓存键:{trigger_key}] [账户:{account.email}] [类型:{sync_type}] [过期时间:60秒]")
        logger.info(f"[API请求] ✓ 触发器数据: {trigger_data}")
        
        # 验证缓存是否设置成功
        cached_value = cache.get(trigger_key)
        if cached_value:
            logger.info(f"[API请求] ✓ 缓存设置验证成功，触发器已就绪 [账户:{account.email}]")
        else:
            logger.error(f"[API请求] ✗ 缓存设置验证失败，触发器未生效 [账户:{account.email}]")
        
        msg = "手动同步任务已提交" if sync_type == 'manual' else "历史邮件同步任务已提交"
        logger.info(f"[API请求] ✓ 响应客户端: {msg} [账户:{account.email}]")
        return success(msg=msg, data={"account_id": account_id, "sync_type": sync_type})
    except Exception as e:
        logger.error(f"[API请求] ✗ 触发同步失败 [账户ID:{account_id}] [错误:{e}]", exc_info=True)
        return fail("提交同步任务失败，请稍后重试")


@router.get("/{account_id}/folders")
async def get_email_folders(
    account_id: int,
    force_sync: bool = Query(default=True, description="是否强制同步，默认为True以保持向后兼容"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取邮箱账户的文件夹列表
    - force_sync=True: 强制从邮件服务器获取最新数据并更新缓存（手动刷新时使用）
    - force_sync=False: 优先使用缓存，缓存不存在时才从服务器获取（移动邮件等操作时使用）
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    # 缓存键：account_folders:{account_id}
    cache_key = f"account_folders:{account_id}"
    
    # 如果不强制同步，先尝试从缓存获取
    if not force_sync:
        cached_data = cache.get(cache_key)
        if cached_data is not None:
            final_folders = cached_data.get("final_folders", [])
            return success(final_folders)
    
    # 强制同步或缓存不存在时，从服务器获取最新文件夹列表 - 异步执行
    try:
        email_service = EmailService(account=account)
        final_folders, folder_mapping = await run_in_executor(
            email_service.get_folders_list,
            force_refresh=force_sync,
            timeout=60.0
        )
        
        # 更新缓存（24小时过期）
        cache_data = {
            "folder_mapping": folder_mapping,
            "final_folders": final_folders
        }
        cache.set(cache_key, cache_data, expire=86400)
        return success(final_folders)
    except Exception as e:
        logger.error(f"获取邮箱文件夹失败: {e}")
        return fail(f"获取邮箱文件夹失败: {str(e)}")


@router.post("/{account_id}/folders", status_code=201)
async def create_folder(
    account_id: int,
    folder: FolderCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    为指定邮箱账户创建新文件夹
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    try:
        email_service = EmailService(account_id=account.id)
        # 异步执行阻塞IO
        success_flag = await run_in_executor(
            email_service.create_folder,
            folder.folder_name,
            folder.parent_folder,
            timeout=60.0
        )
        if success_flag:
            # 清除文件夹缓存
            cache_key = f"account_folders:{account_id}"
            cache.delete(cache_key)
            return success(msg="文件夹创建成功")
        else:
            return fail(msg="文件夹已存在或创建失败")
    except Exception as e:
        return fail(msg=f"创建文件夹时出错: {e}")


@router.put("/{account_id}/folders")
async def rename_folder(
    account_id: int,
    folder_rename: FolderRename,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    重命名或移动指定邮箱账户的文件夹
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    try:
        email_service = EmailService(account_id=account.id)
        # 异步执行阻塞IO
        success_flag = await run_in_executor(
            email_service.rename_folder,
            folder_rename.old_dir,
            folder_rename.new_dir,
            timeout=60.0
        )
        if success_flag:
            # 清除文件夹缓存
            cache_key = f"account_folders:{account_id}"
            cache.delete(cache_key)
            return success(msg="文件夹重命名成功")
        else:
            return fail(msg="文件夹重命名失败")
    except Exception as e:
        return fail(msg=f"重命名文件夹时出错: {e}")

@router.delete("/{account_id}/folders")
async def delete_folder(
    account_id: int,
    folder_data: FolderDelete,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    删除指定账户下的邮件文件夹，并触发后台同步
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    email_service = EmailService(account=account)
    folder_name_to_delete = folder_data.folder_name
    try:
        # 异步执行删除
        await run_in_executor(email_service.delete_folder, folder_name_to_delete, timeout=60.0)
        
        # 清除文件夹缓存
        cache_key = f"account_folders:{account_id}"
        cache.delete(cache_key)
        
        # 文件夹删除成功后，触发一次后台同步
        # 创建一个新的EmailService实例，确保它使用最新的数据库会话
        sync_service = EmailService(account_id=account.id)
        background_tasks.add_task(run_in_executor, sync_service.sync_emails)

        return success(msg=f"文件夹 '{folder_name_to_delete}' 已成功删除，并已开始后台同步。")
    except Exception as e:
        return fail(f"删除文件夹失败: {str(e)}")

@router.put("/{account_id}/status")
async def toggle_account_status(
    account_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    切换邮箱账户的启用/禁用状态
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")
    
    # 切换状态
    new_status = not account.is_active
    account.is_active = new_status
    account.sync_status = "idle"  # 重置同步状态为空闲
    db.commit()
    db.refresh(account)
    
    # 使用缓存系统通知同步服务状态变更
    try:
        # 设置同步触发器，通知同步服务
        trigger_key = f"sync_trigger:{account_id}"
        trigger_data = {
            'type': 'disable' if not new_status else 'enable',
            'timestamp': get_beijing_time().timestamp(),
            'user_id': current_user.id
        }
        cache.set(trigger_key, trigger_data, expire=60)  # 60秒过期
        logger.info(f"已设置状态变更触发器 [账户ID:{account_id}] [操作:{trigger_data['type']}]")
        
        # 验证缓存是否设置成功
        cached_value = cache.get(trigger_key)
        if cached_value:
            logger.info(f"状态变更触发器设置成功 [账户ID:{account_id}]")
        else:
            logger.error(f"状态变更触发器设置失败 [账户ID:{account_id}]")
            
    except Exception as e:
        logger.error(f"设置状态变更触发器失败 [账户ID:{account_id}] [错误:{e}]", exc_info=True)
    
    status_text = "启用" if new_status else "禁用"
    return success({
        "account_id": account_id,
        "is_active": new_status,
        "status_text": status_text
    }, msg=f"邮箱账户已{status_text}")
